﻿using System;
using System.Text;
using Microsoft.Phone.Controls.Maps;

namespace BingleMaps.Models
{
    public abstract class BaseBingMapsSource : TileSource
    {
        private static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
        {
            var quadKey = new StringBuilder();
            for (var i = levelOfDetail; i > 0; i--)
            {
                var digit = '0';
                var mask = 1 << (i - 1);
                if ((tileX & mask) != 0) digit++;
                if ((tileY & mask) != 0)
                {
                    digit++;
                    digit++;
                }
                quadKey.Append(digit);
            }
            return quadKey.ToString();
        }

        public override Uri GetUri(int x, int y, int zoomLevel)
        {
            if (zoomLevel > 0)
            {
                var quadKey = TileXYToQuadKey(x, y, zoomLevel);
                var veLink = string.Format(UriFormat,
                   new object[] { quadKey[quadKey.Length - 1], quadKey });
                return new Uri(veLink);
            }
            return null;
        }
    }

    public class BingMapsRoad : BaseBingMapsSource
    {
        public BingMapsRoad()
        {
            UriFormat = "http://r{0}.ortho.tiles.virtualearth.net/tiles/r{1}.png?g=203&stl=h";
        }
    }

    public class BingMapsAerial : BaseBingMapsSource
    {
        public BingMapsAerial()
        {
            UriFormat = "http://h{0}.ortho.tiles.virtualearth.net/tiles/h{1}.jpeg?g=203";
        }
    }

    public class OsmaRender : TileSource
    {
        public OsmaRender()
        {
            UriFormat = "http://{0}.tah.openstreetmap.org/Tiles/tile/{1}/{2}/{3}.png";
        }

        private readonly static string[] TilePathPrefixes =
          new[] { "a", "b", "c", "d", "e", "f" };

        public override Uri GetUri(int x, int y, int zoomLevel)
        {
            if (zoomLevel > 0)
            {
                var url = string.Format(UriFormat,
                  TilePathPrefixes[(y % 3) + (3 * (x % 2))], zoomLevel, x, y);
                return new Uri(url);
            }
            return null;
        }
    }

    public class Mapnik : TileSource
    {
        public Mapnik()
        {
            UriFormat = "http://{0}.tile.openstreetmap.org/{1}/{2}/{3}.png";
        }

        private readonly static string[] TilePathPrefixes = new[] { "a", "b", "c" };

        public override Uri GetUri(int x, int y, int zoomLevel)
        {
            if (zoomLevel > 0)
            {
                var url = string.Format(UriFormat, TilePathPrefixes[y % 3], zoomLevel, x, y);
                return new Uri(url);
            }
            return null;
        }
    }

    public enum GoogleMapsType
    {
        Street = 'm',
        Hybrid = 'y',
        Satellite = 's',
        Physical = 't',
        PhysicalHybrid = 'p',
        StreetOverlay = 'h',
        WaterOverlay = 'r'
    }

    public class GoogleMapSource : TileSource
    {
        public GoogleMapSource()
        {
            UriFormat = @"http://mt{0}.google.com/vt/lyrs={1}&z={2}&x={3}&y={4}";
        }

        public GoogleMapsType MapType { get; set; }

        public override Uri GetUri(int x, int y, int zoomLevel)
        {
            return new Uri(
              string.Format(UriFormat, (x % 2) + (2 * (y % 2)),
              (char)MapType, zoomLevel, x, y));
        }
    }
}